package com.tools.common.object.string;

import com.tools.common.container.OwnRows;
import com.tools.common.object.Note;

import java.util.Collection;
import java.util.Iterator;
import java.util.regex.Pattern;

/**
 * 常用的正则表达式枚举实例
 * */
@Note("常用的正则表达式枚举实例")
public enum RegEnum {

    @Note("是否是数字，无论正负、整型还是浮点型")
    IS_NUMBER("^[+-]?\\d+(\\.\\d+)?$"),

    @Note("整数（无论正负号），最大限制范围是 Long 的 19 位")
    IS_WHOLE_NUMBER("^([+-]?(?:0|[1-9]\\d{0,18}))$"),

    @Note("小数")
    IS_FLOAT("^[+-]?(\\d*\\.\\d+|\\d+[eE][+-]?\\d+|\\d+\\.\\d*[eE][+-]?\\d+)$|^[+-]?(NaN|Infinity)$\n"),

    @Note("正整数")
    IS_INTEGER("^\\d+\\d*$"),


    @Note("全部是小写字母")
    IS_LOWERCASE("^[a-z]+[a-z]*$"),

    @Note("全部是大写字母")
    IS_UPPERCASE("^[A-Z]+[A-Z]*$"),

    @Note("全部是英文特殊字符")
    IS_EN_SPECIAL("^[-*.=+_/?\\\\@!`~#$%^&()|\\[\\]{}\"';:><]*$"),

    @Note("全部是中文特殊字符")
    IS_CN_SPECIAL("^[！？【】、》《。，；：”“‘’￥…·—（）-]*$"),

    @Note("全部是中文")
    IS_CHINESE("^[\u4e00-\u9fa5]+[\u4e00-\u9fa5]*$"),

    @Note("邮箱")
    IS_EMAIL("^\\s*\\w+(?:\\.?[\\w-]+)*@[a-zA-Z\\d]+(?:[-.][a-zA-Z\\d]+)*\\.[a-zA-Z]+\\s*$"),

    @Note("URL")
    IS_URL("(?i)((ht|f)tp(s?)\\:\\/\\/[\\da-zA-Z]([-.\\w]*[\\da-zA-Z])*(:(0-9)*)*(\\/?)([a-zA-Z\\d\\-\\.\\?\\,\\'\\/\\\\&%\\+\\$#_=]*)?)"),

    @Note("IP:端口")
    IS_HOST_AND_PORT("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5]):(\\d|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$"),

    @Note("端口")
    IS_PORT("^(\\d|[1-9]\\d|[1-9]\\d{2}|[1-9]\\d{3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])$"),

    @Note("IPv4 地址")
    IS_IPV4("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])$"),

    @Note("IPv6 地址")
    IS_IPV6("^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$"),

    @Note("严格判断，手机号码")
    IS_PHONE_STRICT("^(13[0-9]|14[579]|15[0-3,5-9]|16[567]|17[0-8]|18[0-9]|19[0-3,5-9])\\d{8}$"),

    @Note("宽松判断，手机号码")
    IS_PHONE_LOOSE("^1[3-9]\\d{9}$"),

    @Note("座机号码")
    IS_TELE("0\\d{2,3}-\\d{7,8}|\\(?0\\d{2,3}[)-]?\\d{7,8}|\\(?0\\d{2,3}[)-]*\\d{7,8}"),

    @Note("QQ 号")
    IS_QQ("[1-9][0-9]{4,14}"),

    @Note("身份证号码")
    IS_ID("(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)"),

    @Note("银行卡号")
    IS_BANK_CODE("^([1-9])(\\d{14}|\\d{18})$"),

    @Note("邮政编码")
    IS_POST_CODE("^[1-9]\\d{5}$"),

    @Note("车牌号")
    IS_CAR_CODE("([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领 A-Z][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9 挂学警港澳])"),

    @Note("MAC 物理地址。第一份验证规则，此规则判断为 false 则启动第二份判断")
    IS_MAC1("^[A-Fa-f0-9]{2}([-:]?[A-Fa-f0-9]{2})([-:.]?[A-Fa-f0-9]{2})([-:]?[A-Fa-f0-9]{2})([-:.]?[A-Fa-f0-9]{2})([-:]?[A-Fa-f0-9]{2})$"),

    @Note("MAC 物理地址。第二份验证规则")
    IS_MAC2("^[A-Fa-f0-9]{2}(-[A-Fa-f0-9]{2}){5}$|^[A-Fa-f0-9]{2}(:[A-Fa-f0-9]{2}){5}$|^[A-Fa-f0-9]{12}$|^[A-Fa-f0-9]{4}(\\.[A-Fa-f0-9]{4}){2}$"),

    @Note("包含中文")
    CONTAINS_CHINESE("[\u4e00-\u9fa5]+"),

    @Note("包含数字")
    CONTAINS_NUMBER(".*[0-9]+.*"),

    @Note("包含小写字母")
    CONTAINS_LOWERCASE(".*[a-z]+.*"),

    @Note("包含大写字母")
    CONTAINS_UPPERCASE(".*[A-Z]+.*"),

    @Note("包含英文的特殊字符")
    CONTAINS_EN_SPECIAL(".*[-*.=+_/?\\\\@!`~#$%^&()|\\[\\]{}\"';:><]+.*"),

    @Note("包含中文的特殊字符")
    CONTAINS_CN_SPECIAL(".*[！？【】、》《。，；：”“‘’￥…·—（）-]+.*"),

    @Note("以数字开头")
    BEGIN_NUMBER("^[0-9]"),

    @Note("以小写字母开头")
    BEGIN_LOWERCASE("^[a-z]"),

    @Note("以大写字母开头")
    BEGIN_UPPERCASE("^[A-Z]"),

    @Note("以英文特殊字符开头")
    BEGIN_EN_SPECIAL("^[-*.=+_/?\\\\@!`~#$%^&()|\\[\\]{}\"';:><]"),

    @Note("以中文特殊字符开头")
    BEGIN_CN_SPECIAL("^[！？【】、》《。，；：”“‘’￥…·—（）-]"),

    @Note("以中文开头")
    BEGIN_CHINESE("^[\u4e00-\u9fa5]"),

    @Note("以数字结尾")
    END_NUMBER("[0-9]$"),

    @Note("以小写字母结尾")
    END_LOWERCASE("[a-z]$"),

    @Note("以大写字母结尾")
    END_UPPERCASE("[A-Z]$"),

    @Note("以英文特殊字符结尾")
    END_EN_SPECIAL("[-*.=+_/?\\\\@!`~#$%^&()|\\[\\]{}\"';:><]$"),

    @Note("以中文特殊字符结尾")
    END_CN_SPECIAL("[！？【】、》《。，；：”“‘’￥…·—（）-]$"),

    @Note("以中文结尾")
    END_CHINESE("[\u4e00-\u9fa5]$");

    /* ************************************************************************************************************
     *
     *          属性和构造器
     *
     * ************************************************************************************************************
     * */

    @Note("正则匹配规则字符串")
    private final String regex;

    @Note("正则实例")
    private Pattern pattern;

    RegEnum(String regex) {
        this.regex = regex;
    }

    public String getRegex() {
        return regex;
    }

    @Override
    public String toString() {
        return regex;
    }

    /* ************************************************************************************************************
     *
     *          其他方法
     *
     * ************************************************************************************************************
     * */

    @Note("懒加载获取正则匹配实例对象")
    public Pattern getPattern() {
        if(pattern != null) return pattern;
        synchronized (this) {
            if(pattern != null) return pattern;
            this.pattern = Pattern.compile(this.regex);
        }
        return pattern;
    }


    @Note("使用 this 的正则匹配目标字符串 s")
    public boolean match(String s) {
        return s != null && !s.isEmpty() && this.getPattern().matcher(s).find();
    }


    @Note("数组里的所有字符串匹配为 true 才返回 true")
    public boolean matchAll(String... s) {
        if(s == null || s.length == 0) return false;
        for (String str : s) if(!match(str)) return false;
        return true;
    }


    @Note("Collection 集合里的所有字符串匹配为 true 才返回 true")
    public boolean matchAll(Collection<String> s) {
        if(s == null || s.isEmpty()) return false;
        for (String str : s) if(!match(str)) return false;
        return true;
    }


    @Note("自定义容器集合里的所有字符串匹配为 true 才返回 true")
    public boolean matchAll(OwnRows<String> s) {
        if(s == null || s.isEmpty()) return false;
        for (String str : s) if(!match(str)) return false;
        return true;
    }

    @Note("可迭代容器里的所有字符串匹配为 true 才返回 true")
    public boolean matchAll(Iterable<String> s) {
        if(s instanceof Collection) return matchAll((Collection<String>) s);
        if(s instanceof OwnRows) return matchAll((OwnRows<String>) s);
        if(s == null) return false;
        Iterator<String> iterator = s.iterator();
        if(!iterator.hasNext()) return false;
        while (iterator.hasNext()) {
            if(!match(iterator.next())) return false;
        }
        return true;
    }


    @Note("数组里的任意一个字符串匹配为 true 则返回 true")
    public boolean matchAny(String... s) {
        if(s == null || s.length == 0) return false;
        for (String str : s) if(match(str)) return true;
        return false;
    }


    @Note("Collection 集合里的任意一个字符串匹配为 true 则返回 true")
    public boolean matchAny(Collection<String> s) {
        if(s == null || s.isEmpty()) return false;
        for (String str : s) if(match(str)) return true;
        return false;
    }

    @Note("自定义容器集合里的任意一个字符串匹配为 true 则返回 true")
    public boolean matchAny(OwnRows<String> s) {
        if(s == null || s.isEmpty()) return false;
        for (String str : s) if(match(str)) return true;
        return false;
    }


    @Note("可迭代容器里的任意一个字符串匹配为 true 则返回 true")
    public boolean matchAny(Iterable<String> s) {
        if(s instanceof Collection) return matchAny((Collection<String>) s);
        if(s instanceof OwnRows) return matchAny((OwnRows<String>) s);
        if(s == null) return false;
        Iterator<String> iterator = s.iterator();
        if(!iterator.hasNext()) return false;
        while (iterator.hasNext()) {
            if(match(iterator.next())) return true;
        }
        return false;
    }
}
